#ifndef mswin_timing_node_h
#define mswin_timing_node_h

#include <vector>
#include <map>
#include <cassert>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "undef_min_max.h"

namespace mswin {

struct time : FILETIME
{
	time(DWORD low = 0, DWORD high = 0) {
		dwLowDateTime = low;
		dwHighDateTime = high;
	}
	time(ULONGLONG ulonglong) {
		ULARGE_INTEGER ulint;
		ulint.QuadPart = ulonglong;
		dwLowDateTime = ulint.LowPart; 
		dwHighDateTime = ulint.HighPart; 
	}
	time(double s) {
		dwHighDateTime =  static_cast<DWORD>(s / 429.4967296); 
		dwLowDateTime = static_cast<DWORD>((s - dwHighDateTime * 429.4967296) / 0.0000001); 
	}
	operator ULONGLONG () const {
		ULARGE_INTEGER res;
		res.LowPart = dwLowDateTime; 
		res.HighPart = dwHighDateTime; 
		return res.QuadPart;
	}
	friend bool operator == (const time & lhs, const time & rhs)
		{ return lhs.dwHighDateTime == rhs.dwHighDateTime && lhs.dwLowDateTime == rhs.dwLowDateTime; }
	friend bool operator != (const time & lhs, const time & rhs)
		{ return lhs.dwHighDateTime != rhs.dwHighDateTime || lhs.dwLowDateTime != rhs.dwLowDateTime; }
	double seconds() const 
		{ return 429.4967296 * dwHighDateTime + 0.0000001 * dwLowDateTime; }
	friend time operator + (const time & i1, const time & i2) 
		{ return time(ULONGLONG(i1) + ULONGLONG(i2)); }
	friend time operator - (const time & i1, const time & i2) 
		{ return time(ULONGLONG(i1) - ULONGLONG(i2)); }
	time & operator += (const time & rhs)
		{ return *this = *this + rhs; }
	time & operator -= (const time & rhs)
		{ return *this = *this - rhs; }
	friend std::istream & operator >> (std::istream & s, time & t) {
		double d;
		s >> d;
		t = time(d);
		return s;
	}
	friend std::ostream & operator << (std::ostream & s, const time & t) 
		{ return s << t.seconds(); }
};

//node info

struct node_info {
	int nesting;
	const timing_tree::node * ptr;

	node_info() { }
	node_info(int n, const timing_tree::node * p) : nesting(n), ptr(p) { }
};

typedef std::vector<node_info> nodes_enumerated;

//node

struct timing_tree::node
{
	node(std::string node_name) : name(node_name) 
	{
		calls_count = 0;
		node_count.QuadPart = subtree_count.QuadPart = entrance_count.QuadPart = 0;
	}
	~node();
	node & operator = (const node & rhs);
	node & operator += (const node & rhs);
	node * open(const std::string & name);

	template <class F> 
	void for_each_child(F f);

	void enumerate_children(nodes_enumerated & v, int nesting) const;
	bool has_child() const
		{ return !children.empty(); }
	unsigned num_children() const
		{ return children.size(); }

	std::string name;
	unsigned calls_count;
	//cpu times
	time node_time;
	time subtree_time;
	time entrance_time;
	//world times
	LARGE_INTEGER node_count;
	LARGE_INTEGER subtree_count;
	LARGE_INTEGER entrance_count;

private:
	typedef std::map<std::string, node *> children_type;
	children_type children;
private:
	struct deleter {
		void operator () (children_type::value_type & i) 
			{ delete i.second; }
	};
};

typedef timing_tree::node node;


template <class F> 
void node::for_each_child(F f)
{
	children_type::iterator i;
	for (i = children.begin(); i != children.end(); ++i)
		f(*i->second);
}

} //namespace mswin

#endif //mswin_timing_node_h
